package com.stellar.wechat.core.common;

import com.fasterxml.jackson.databind.JsonNode;
import com.stellar.wechat.config.WxMiniProgramConfig;
import com.stellar.wechat.core.common.exception.WxApiException;
import com.stellar.wechat.core.enums.WxErrorCode;
import com.stellar.wechat.core.storage.TokenStorage;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Jqcc
 * @Version 1.0
 * @Data 2025/3/31
 * @Description 微信 AccessToken 工具类
 */
@Service
public class AccessTokenUtil {

    private final WxMiniProgramConfig config;

    private final WxHttpClient wxHttpClient;

    private final TokenStorage tokenStorage;

    private final ReentrantLock lock = new ReentrantLock();


    public AccessTokenUtil(WxMiniProgramConfig config, WxHttpClient wxHttpClient, TokenStorage tokenStorage) {
        this.config = config;
        this.wxHttpClient = wxHttpClient;
        this.tokenStorage = tokenStorage;
    }

    /**
     * 获取微信 AccessToken
     *
     * @param forceRefresh 是否强制刷新
     * @return 有效的 AccessToken
     * @throws WxApiException 微信接口错误时抛出
     */
    public synchronized String getAccessToken(boolean forceRefresh) throws WxApiException {

        // 非强制刷新时尝试获取缓存
        if (!forceRefresh) {
            String cachedToken = tokenStorage.getToken(false);
            if (cachedToken != null) {
                return cachedToken;
            }
        }

        // 获取锁
        lock.lock();

        try {
            // 双重检查锁定
            if (!forceRefresh) {
                String cached = tokenStorage.getToken(false);
                if (cached != null) return cached;
            }

            // 构建请求URL
            URI uri = URI.create(String.format("%s/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                    config.getApiBaseUrl(),
                    config.getAppId(),
                    config.getAppSecret()));

            // 调用微信接口
            JsonNode response = wxHttpClient.get(uri, JsonNode.class);

            if (response.has("errcode") && response.get("errcode").asInt() != 0) {
                throw new WxApiException(
                        response.get("errcode").asInt(),
                        response.get("errmsg").asText()
                );
            }

            // 解析并存储Token
            String newToken = response.get("access_token").asText();
            int expiresIn = response.get("expires_in").asInt();
            tokenStorage.storeToken(newToken, expiresIn);

            return newToken;
        } catch (IOException e) {
            throw new WxApiException(WxErrorCode.TOKEN_GET_NETWORK_ERROR);
        } finally {
            // 释放锁
            lock.unlock();
        }
    }
}
